/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package Simulator;

/**
 * The Cntl class will handle and CNTL or STACK operations.  This is called directly from the Control class.
 * @author khhill
 */
public class Cntl {
    Control control_instance = new Control();
    
                /**
    * The Halt function is called when the function bits are 000.  It stops the operation of the program.
    * <p>
    * <b>Change Log:</b><br>
    * None<br>
    * <p>
    * <b>Error Conditions Tested:</b><br>
    * None <br>
    * <p>
    * <b>Date of module being installed:</b> 5/21/08
    * <p><b>Original Author:</b>  Keith Hill
    * @return returns 1 always.  This is to follow the format for the rest of the Cntl class.
    */
    public static int Halt(){
        int return_result = 1;
        Control.finished = true;
        
        return return_result;
    }
    
        /**
    * Dumps the contents of stacks and memory to the screen depending on the 
    * parameter.
    * <p>
    * <b>Change Log:</b><br>
    * 5/23/2008 - Create Skeleton - Keith Hill<br>
    * 5/24/2008 - Implement Functionality - Peter Dietz<br>
    * <p>
    * <b>Error Conditions Tested:</b><br>
    * 107 - Operand not valid for dump<br>
    * <p>
    * <b>Date of module being installed:</b> 5/23/2008
    * <p><b>Original Author:</b>  Peter Dietz
    * @param bit_code binary to be used to retrieve the operand value
    * @param lit_flag literal flag, unused
    * @return integer for success, 1 for good, 2000 for the error
    */    
    public static int Dump(String bit_code, String lit_flag){
        // peter: This will get you the operand value that you need.
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);
        Stack stack_instance = new Stack();
        Control control_instance = new Control();
        switch (operand) {
            case 1:  
                stack_instance.PrintStatusStack();
                break;
            
            case 2:  
                stack_instance.PrintDataStack();
                break;
            
            case 4:  
                stack_instance.PrintTestStack();
                break;
            
            case 8:  
                control_instance.dumpMem();
                break;
            
            case 15: 
                //prints all stacks and memory
                stack_instance.PrintDataStack();
                stack_instance.PrintStatusStack();
                stack_instance.PrintTestStack();
                control_instance.dumpMem();
                break;
            
            default: 
                IceAssembly.Initialize initialize_instance = new IceAssembly.Initialize();
                initialize_instance.printErrorMessage(106); //invalid parameter for binary5
                return_value = 2000;
                break;
        }
        
        return return_value;
    }
    
               /**
* The Goto function will be called when the function bits are 010.  The function will first get an integer value from the bit code in the operand 
     * field from the instruction.  Then, if the literal flag determines that it is a label, 
     * the function will find the value in that memory location and use that as the operand value.  
     * The function then changes the location value to the desired location.
* <p>
* <b>Change Log:</b><br>
* None<br>
* <p>
* <b>Error Conditions Tested:</b><br>
* 008 - Attempting to jump to a location undefined in memory.  Terminating execution. <br>
* 009 - Attempting to retrieve data in memory that is not defined for a GOTO operation.  Terminating execution.<br>
* <p>
* <b>Date of module being installed:</b> 5/21/08
* <p><b>Original Author:</b>  Keith Hill
* @param bit_code This is the 10 digit bit code that determines the value of the operand to be processed.
     * @param lit_flag This is the one digit bit code that flags if the operand is a literal or not.
* @return 1 is returned if the operation was completed successfully without errors.  2000 is returned if the operation isn't completed correctly.  4000 is returned if a divide by 0 is encountered. 3000 is returned if an invalid memory reference was found.
*/ 
    public static int Goto(String bit_code,String lit_flag){
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);
        
            if(Control.memory[operand].equals("x")){
                System.out.println("Error 009:  Attempting to retrieve data in memory that is not defined for a GOTO operation.  Terminating execution.");               
                return_value = 3000;
                Control.finished = true;
                return return_value;
            }
            else{
                operand = Integer.parseInt(Control.memory[operand],16);
            }          
        
        
        if(Control.memory[operand].equals("x")){
            System.out.println("Error 008: Attempting to jump to a location undefined in memory.  Terminating execution.");
            return_value = 2000;
            Control.finished = true;
        }
        else{
            Control.location_counter = operand;
        }        
        return return_value;
    }
    
               /**
* The Clrs function will be called when the function bits are 011.  The function will first get an integer value from the bit code in the operand 
     * field from the instruction.  Then, if the literal flag determines that it is a label, 
     * the function will find the value in that memory location and use that as the operand value.  
     * The function then clears the desired stack(s).
* <p>
* <b>Change Log:</b><br>
* None<br>
* <p>
* <b>Error Conditions Tested:</b><br>
* 174 - Operand doesn't match an available operand for this function.<br>
* <p>
* <b>Date of module being installed:</b> 5/21/08
* <p><b>Original Author:</b>  Keith Hill
* @param bit_code This is the 10 digit bit code that determines the value of the operand to be processed.
     * @param lit_flag This is the one digit bit code that flags if the operand is a literal or not.
* @return 1 is returned if the operation was completed successfully without errors.  2000 is returned if the operation isn't completed correctly.  4000 is returned if a divide by 0 is encountered. 3000 is returned if an invalid memory reference was found.
*/    
    public static int Clrs(String bit_code,String lit_flag){
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);
        
        int tempi = 0;
        String temps = "";
        if(operand == 1){
            while(Stack.status_stack_size>0){
                temps = Stack.PopStatus();
            }
        }
        else if(operand == 2){
            while(Stack.data_stack_size>0){
                tempi = Stack.PopData();
            }
        }
        else if(operand == 4){
            while(Stack.test_stack_size>0){
                tempi = Stack.PopTest();
            }
        }
        else if(operand == 8){
            while(Stack.data_stack_size>0){
                tempi = Stack.PopData();
            }
            while(Stack.test_stack_size>0){
                tempi = Stack.PopTest();
            }
            while(Stack.status_stack_size>0){
                temps = Stack.PopStatus();
            }
        }
        else {
            System.out.println("Error 174: Operand doesn't match an available operand for this function.");
            return_value = 2000;
        }
        
        
        return return_value;
    
    }
    
                   /**
* The Pushd function will be called when the function bits are 100.  The function will first get an integer value from the bit code in the operand 
     * field from the instruction.  Then, if the literal flag determines that it is a label, 
     * the function will find the value in that memory location and use that as the operand value.  
     * The function then pushes the desired value to the data stack.
* <p>
* <b>Change Log:</b><br>
* None<br>
* <p>
* <b>Error Conditions Tested:</b><br>
* 169 - Error 169:  Value at memory not defined.  0 substituted.<br>
* <p>
* <b>Date of module being installed:</b> 5/24/08
* <p><b>Original Author:</b>  Keith Hill
* @param bit_code This is the 10 digit bit code that determines the value of the operand to be processed.
     * @param lit_flag This is the one digit bit code that flags if the operand is a literal or not.
* @return 1 is returned if the operation was completed successfully without errors.  2000 is returned if the operation isn't completed correctly.  4000 is returned if a divide by 0 is encountered. 3000 is returned if an invalid memory reference was found.
*/ 
    
    public static int Pushd(String bit_code,String lit_flag){
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);
        if(lit_flag.equals("0")){
            if(Control.memory[operand].equals("x")){
                System.out.println("Error 169:  Value at memory not defined.  0 substituted.");
                operand = 0;
                return_value = 3000;
            }
            else{
                operand = Integer.parseInt(Control.memory[operand],16);
            }
        }
        
        
        return_value = Stack.PushData(operand);
        
        return return_value;
    }
    
                    /**
* The Popd function will be called when the function bits are 101.  The function will first get an integer value from the bit code in the operand 
     * field from the instruction.  Then, if the literal flag determines that it is a label, 
     * the function will find the value in that memory location and use that as the operand value.  
     * The function then pops the desired value from the data stack.
* <p>
* <b>Change Log:</b><br>
* None<br>
* <p>
* <b>Error Conditions Tested:</b><br>
* 169 - Error 169:  Value at memory not defined.  0 substituted.<br>
 *176 - Attempting to write to a location outside of the scope of this program.<br>
* <p>
* <b>Date of module being installed:</b> 5/24/08
* <p><b>Original Author:</b>  Keith Hill
* @param bit_code This is the 10 digit bit code that determines the value of the operand to be processed.
     * @param lit_flag This is the one digit bit code that flags if the operand is a literal or not.
* @return 1 is returned if the operation was completed successfully without errors.  2000 is returned if the operation isn't completed correctly.  4000 is returned if a divide by 0 is encountered. 3000 is returned if an invalid memory reference was found.
*/ 
    
    public static int Popd(String bit_code,String lit_flag){
        IceAssembly.Convert convert_instance = new IceAssembly.Convert();
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);
            if(Control.memory[operand].equals("x")){
                System.out.println("Error 169:  Value at memory not defined.  0 substituted.");
                operand = 0;
                return_value = 3000;
            }
        
        
        int top_of_stack = Stack.PopData();          
        String top_of_stacks = convert_instance.intToFourHex(top_of_stack);
        
        if(operand<Control.starting_location || operand > Control.max_location){
         System.out.println("Error 176: Attempting to write to a location in memory outside of the scope of this program.  Line ignored.");   
         return_value = 2000;
        }
        else{
            Control.memory[operand] = top_of_stacks;
        }
        
        
        
        return return_value;
    }
    
    
                      /**
* The Test function will be called when the function bits are 110.  The function will first get an integer value from the bit code in the operand 
     * field from the instruction.  Then, if the literal flag determines that it is a label, 
     * the function will find the value in that memory location and use that as the operand value.  
     * The function then pops the value from the data stack, compares it with the operand, and pushes a value to the test stack.
* <p>
* <b>Change Log:</b><br>
* None<br>
* <p>
* <b>Error Conditions Tested:</b><br>
* 169 - Error 169:  Value at memory not defined.  0 substituted.<br>
* <p>
* <b>Date of module being installed:</b> 5/24/08
* <p><b>Original Author:</b>  Keith Hill
* @param bit_code This is the 10 digit bit code that determines the value of the operand to be processed.
     * @param lit_flag This is the one digit bit code that flags if the operand is a literal or not.
* @return 1 is returned if the operation was completed successfully without errors.  2000 is returned if the operation isn't completed correctly.  4000 is returned if a divide by 0 is encountered. 3000 is returned if an invalid memory reference was found.
*/ 
    
    public static int Test(String bit_code,String lit_flag){
        IceAssembly.Convert convert_instance = new IceAssembly.Convert();
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);
        if(lit_flag.equals("0")){
            if(Control.memory[operand].equals("x")){
                System.out.println("Error 169:  Value at memory not defined.  0 substituted.");
                operand = 0;
                return_value = 3000;
            }
            else{
                operand = Integer.parseInt(Control.memory[operand],16);
            }
        }
        
        
        int top_of_stack = Stack.PopData();                 
        
        if(top_of_stack == operand){
            Stack.PushTest(0);
        }
        else if (top_of_stack < operand){
            Stack.PushTest(2);
        }
        else{
            Stack.PushTest(3);
        }
        
        return return_value;
    }
    
                      /**
* The Pops function will be called when the function bits are 111.  The function will first get an integer value from the bit code in the operand 
     * field from the instruction.  Then, if the literal flag determines that it is a label, 
     * the function will find the value in that memory location and use that as the operand value.  
     * The function then pops the desired value from the status stack and writes it to memory.
* <p>
* <b>Change Log:</b><br>
* None<br>
* <p>
* <b>Error Conditions Tested:</b><br>
* 169 - Error 169:  Value at memory not defined.  0 substituted.<br>
 *176 - Attempting to write to a location outside of the scope of this program.<br>
* <p>
* <b>Date of module being installed:</b> 5/24/08
* <p><b>Original Author:</b>  Keith Hill
* @param bit_code This is the 10 digit bit code that determines the value of the operand to be processed.
     * @param lit_flag This is the one digit bit code that flags if the operand is a literal or not.
* @return 1 is returned if the operation was completed successfully without errors.  2000 is returned if the operation isn't completed correctly.  4000 is returned if a divide by 0 is encountered. 3000 is returned if an invalid memory reference was found.
*/ 
    
    public static int Pops(String bit_code,String lit_flag){        
        int return_value = 1;
        int operand = Integer.parseInt(bit_code, 2);        
            if(Control.memory[operand].equals("x")){
                System.out.println("Error 169:  Value at memory not defined.  0 substituted.");
                operand = 0;
                return_value = 3000;
            }
        
        
        String top_of_stack = Stack.PopStatus();                  
        
        if(operand<Control.starting_location || operand > Control.max_location){
         System.out.println("Error 176: Attempting to write to a location in memory outside of the scope of this program.  Line ignored.");   
         return_value = 2000;
        }
        else{
            Control.memory[operand] = top_of_stack;
        }
        
        
        
        return return_value;
    }
   
            /**
    * The Control function will recive the call from the Simulator's Control class.  It will receive the bit 
         * information.  It will start by throwing away the first two bits since they are no longer needed.  It will then 
         * check the next three bits and call the appropriate function class with the literal flag and the operand bits as 
         * parameters.
    * <p>
    * <b>Change Log:</b><br>
    * None<br>
    * <p>
    * <b>Error Conditions Tested:</b><br>
    * None <br>
    * <p>
    * <b>Date of module being installed:</b> 5/19/08
    * <p><b>Original Author:</b>  Keith Hill
    * @param bit_code This is the incomming bit code that will be processed.
    */
    public static void Control(String bit_code){
        bit_code = bit_code.replaceFirst("00", "");
        String function = bit_code.substring(0, 3);
        bit_code = bit_code.replaceFirst(function, "");
        String lit_flag = bit_code.substring(0,1);
        bit_code = bit_code.replaceFirst(lit_flag, "");
        
        int result = 0;
        if(function.equals("000")){
            result = Halt();
        }
        else if(function.equals("001")){
            result = Dump(bit_code,lit_flag);
            Control.location_counter++;
        }
        else if(function.equals("010")){
            result = Goto(bit_code,lit_flag);
            
        }
        else if(function.equals("011")){
            result = Clrs(bit_code,lit_flag);
            Control.location_counter++;
        }
        else if(function.equals("100")){
            result = Pushd(bit_code,lit_flag);
            Control.location_counter++;
        }
        else if(function.equals("101")){
            result = Popd(bit_code,lit_flag);
            Control.location_counter++;
        }
        else if(function.equals("110")){
            result = Test(bit_code,lit_flag);
            Control.location_counter++;
        }
        else if(function.equals("111")){
            result = Pops(bit_code,lit_flag);
            Control.location_counter++;
        }
        else{
            System.out.println("How the fuck did that happen?");
        }
        if(!function.equals("111")){
            IceAssembly.Convert convert_instance = new IceAssembly.Convert();
            String status_result=convert_instance.getBitCode(String.valueOf(Control.location_counter), 10);
            if(result == 1){
                status_result =  "000000"+status_result;
            }
            else if(result == 1000){
                status_result = "110000"+status_result;
            }
            else if(result == 2000){
                status_result = "100000"+status_result;
            }
            else if(result ==3000){
                status_result = "000001"+status_result;
            }
            status_result = convert_instance.binaryToHex(status_result);
            while(status_result.length()<4){
                status_result = "0" + status_result;
            }
            Stack.PushStatus(status_result);
        }
        
    }

}
